package com.xdw.camerabyjava.slice;

import com.xdw.camerabyjava.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.camera.CameraKit;
import ohos.media.camera.device.*;
import ohos.media.image.ImageReceiver;
import ohos.media.image.common.ImageFormat;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PICTURE;
import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PREVIEW;

public class TakePhotoAbilitySlice extends AbilitySlice {
    private static final HiLogLabel LABEL = new HiLogLabel(0, 0, "TakePhotoAbilitySlice.class");
    private CameraStateCallback cameraStateCallback = new CameraStateCallbackImpl();
    // 执行回调的EventHandler
    EventHandler eventHandler = new EventHandler(EventRunner.create("CameraCb"));
    private static final int SCREEN_WIDTH = 1080;

    private static final int SCREEN_HEIGHT = 1920;
    // 相机设备
    private Camera cameraDevice;
    // 相机预览模板
    private Surface previewSurface;
    // 相机配置模板
    private CameraConfig.Builder cameraConfigBuilder;
    private SurfaceProvider surfaceProvider;
    private FrameConfig.Builder frameConfigBuilder;
    private FrameConfig previewFrameConfig;

    private Component buttonGroupLayout;

    private ComponentContainer surfaceContainer;

    private ImageReceiver imageReceiver;
    // 前置相机类型
    int frontCamera = CameraInfo.FacingType.CAMERA_FACING_FRONT;
    // 后置相机类型
    int backCamera = CameraInfo.FacingType.CAMERA_FACING_BACK;
    // 其他相机类型
    int otherCamera = CameraInfo.FacingType.CAMERA_FACING_OTHERS;
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_take_photo);
        initComponents();
        initSurface();
    }

    private void openCamera(){
        takePictureInit();
        openCameraByFacingType(frontCamera);
    }

    // 根据类型创建相机的方法
    private boolean openCameraByFacingType(int facingType) {
        CameraKit cameraKit = CameraKit.getInstance(getApplicationContext());
        for(String cameraId : cameraKit.getCameraIds()) {
            CameraInfo cameraInfo = cameraKit.getCameraInfo(cameraId);
            if(facingType == cameraInfo.getFacingType()) {
                cameraKit.createCamera(cameraId, cameraStateCallback, eventHandler);
                return true;
            }
        }
        return false;
    }

    private final class CameraStateCallbackImpl extends CameraStateCallback {
        @Override
        public void onCreated(Camera camera) {
            // 创建相机设备
            previewSurface = surfaceProvider.getSurfaceOps().get().getSurface();
            cameraConfigBuilder = camera.getCameraConfigBuilder();
            if (cameraConfigBuilder == null) {
                HiLog.error(LABEL, "onCreated cameraConfigBuilder is null");
                return;
            }
            // 配置预览的Surface
            cameraConfigBuilder.addSurface(previewSurface);
            cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
            try {
                // 相机设备配置
                camera.configure(cameraConfigBuilder.build());
            } catch (IllegalArgumentException e) {
                HiLog.error(LABEL, "Argument Exception");
            } catch (IllegalStateException e) {
                HiLog.error(LABEL, "State Exception");
            }
            cameraDevice =camera;
        }

        @Override
        public void onConfigured(Camera camera) {
            // 配置相机设备
            // 获取预览配置模板
            frameConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW);
            // 配置预览Surface
            frameConfigBuilder.addSurface(previewSurface);
            previewFrameConfig = frameConfigBuilder.build();
            try {
                // 启动循环帧捕获
                int triggerId = camera.triggerLoopingCapture(previewFrameConfig);
            } catch (IllegalArgumentException e) {
                HiLog.error(LABEL, "Argument Exception");
            } catch (IllegalStateException e) {
                HiLog.error(LABEL, "State Exception");
            }
        }

        @Override
        public void onPartialConfigured(Camera camera) {
            // 当使用了addDeferredSurfaceSize配置了相机，会接到此回调
        }

        @Override
        public void onReleased(Camera camera) {
            // 释放相机设备
        }
    }

    private void initSurface() {
        getWindow().setTransparent(true);
        surfaceProvider = new SurfaceProvider(this);
        DirectionalLayout.LayoutConfig params = new DirectionalLayout.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
        surfaceProvider.setLayoutConfig(params);
        surfaceProvider.pinToZTop(false);
        surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceCallBack());
        ((ComponentContainer)
                findComponentById(ResourceTable.Id_surface_container)).addComponent(surfaceProvider);
    }


    private class  SurfaceCallBack implements SurfaceOps.Callback{

        @Override
        public void surfaceCreated(SurfaceOps surfaceOps) {
            eventHandler.postTask(TakePhotoAbilitySlice.this::openCamera,200);
        }

        @Override
        public void surfaceChanged(SurfaceOps surfaceOps, int i, int i1, int i2) {

        }

        @Override
        public void surfaceDestroyed(SurfaceOps surfaceOps) {

        }
    }

    private void initComponents() {
        buttonGroupLayout = findComponentById(ResourceTable.Id_directionalLayout);
        surfaceContainer = (ComponentContainer) findComponentById(ResourceTable.Id_surface_container);
        Image takePhotoImage = (Image) findComponentById(ResourceTable.Id_tack_picture_btn);
        Image exitImage = (Image) findComponentById(ResourceTable.Id_exit);
        Image switchCameraImage = (Image) findComponentById(ResourceTable.Id_switch_camera_btn);
        exitImage.setClickedListener(component -> terminateAbility());
        takePhotoImage.setClickedListener(this::takeSingleCapture);

    }

    private void takeSingleCapture(Component component){
        // 获取拍照配置模板
        FrameConfig.Builder framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(FRAME_CONFIG_PICTURE);
        // 配置拍照Surface
        framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
        // 配置拍照其他参数
        framePictureConfigBuilder.setImageRotation(90);
        try {
            // 启动单帧捕获(拍照)
            cameraDevice.triggerSingleCapture(framePictureConfigBuilder.build());
        } catch (IllegalArgumentException e) {
            HiLog.error(LABEL, "Argument Exception");
        } catch (IllegalStateException e) {
            HiLog.error(LABEL, "State Exception");
        }
    }

    private void takePictureInit() {

        imageReceiver = ImageReceiver.create(SCREEN_WIDTH,SCREEN_HEIGHT, ImageFormat.JPEG, 5); // 创建ImageReceiver对象，注意create函数中宽度要大于高度；5为最大支持的图像数，请根据实际设置。
        imageReceiver.setImageArrivalListener(new ImageReceiver.IImageArrivalListener() {
            @Override
            public void onImageArrival(ImageReceiver imageReceiver) {
                HiLog.info(LABEL, "onImageArrival");
                saveImage(imageReceiver);
            }
        });
    }

    private void saveImage(ImageReceiver receiver) {
//        showTips(getContext(),"saveImage");
        File saveFile = new File(getExternalFilesDir(null), "IMG_" + System.currentTimeMillis() + ".jpg");
        ohos.media.image.Image image = receiver.readNextImage();
        ohos.media.image.Image.Component component = image.getComponent(ImageFormat.ComponentType.JPEG);
        byte[] bytes = new byte[component.remaining()];
        component.read(bytes);
        try (FileOutputStream output = new FileOutputStream(saveFile)) {
            output.write(bytes);
            output.flush();
            String msg = "Take photo succeed, path=" + saveFile.getPath();
        } catch (IOException e) {
            HiLog.error(LABEL, "%{public}s", "saveImage IOException");
        }
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}
